package com.axapoint.opoc.core.dao;

import java.util.Collection;
import java.util.LinkedList;

import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.Table;

import org.hibernate.annotations.Cascade;
import org.joda.time.DateTime;
import org.joda.time.Interval;

import com.anasoft.os.daofusion.bitemporal.WrappedBitemporalProperty;
import com.anasoft.os.daofusion.bitemporal.WrappedValueAccessor;

@Entity
@Table(name = "Location")
public class Location extends ObjectRegistration<Location, Location.Value, Location.Bitemporal> {
	private static final long serialVersionUID = 9168710745762860711L;

	@Entity
	@Table(name = "LocationValue")
	public static final class Value extends _Value<Location, Location.Bitemporal> {
		private static final long serialVersionUID = 1L;
		private String address;
				
		@SuppressWarnings("deprecation")
		@ManyToOne(fetch = FetchType.LAZY)
	    @Cascade(value = { org.hibernate.annotations.CascadeType.ALL, org.hibernate.annotations.CascadeType.DELETE_ORPHAN })
	    @JoinColumn(name="postalDistrictId")
		private PostalDistrict postalDistrict;

		protected Value() {};
		Value(Location location, String systemId, String userId, Operation operation, String comment, Value value) {
			super(location, systemId, userId, operation, comment);
			this.address = value.address;
			this.postalDistrict = value.postalDistrict;
		}
		public Value(String address, PostalDistrict postalDistrict) {
			this.address = address;
			this.postalDistrict = postalDistrict;
		}
		public String getAddress() {
			return address;
		}
		protected void setAddress(String address) {
			this.address = address;
		}
		public PostalDistrict getPostalDistrict() {
			return postalDistrict;
		}
		protected void setPostalDistrict(PostalDistrict postalDistrict) {
			this.postalDistrict = postalDistrict;
		}
		
		@Override
		protected String diff(_Value<Location, Bitemporal> otherValue, DateTime t0, DateTime t1) {
			StringBuffer sb = new StringBuffer();
			Value other = (Value)otherValue;
			
			if (!address.equals(other.address)) {
				sb.append("Location.address: ").append(address).append(" - ").append(other.address).append('\n');
			}
			PostalDistrict.Bitemporal pd0 = getPostalDistrict().getValues().get(t0);
			PostalDistrict.Bitemporal pd1 = getPostalDistrict().getValues().get(t1);

			if (!pd0.getValue().getEntity().equals(pd1.getValue().getEntity()) ||
				!pd0.getValue().equals(pd1.getValue())) {
				sb.append("Location.postalDistrict: ");
				sb.append('[').append(pd0.getValue().getEntity().getUuid()).append("] ").append(pd0.getValue().getName()).append(" - ");
				sb.append('[').append(pd0.getValue().getEntity().getUuid()).append("] ").append(pd1.getValue().getName()).append('\n');
			}
			
			return sb.toString();
		}
		
		@Override
		public String toString() {
			StringBuffer sb = new StringBuffer();
			sb.append(super.toString());
			sb.append("  address=").append(address).append('\n');
			sb.append("  postalDistrict=").append(getPostalDistrict().getValues().get(getBitemporal().getValidityInterval().getStart()).getValue().getName()).append('\n');

			return sb.toString();
		}
	}
	
	@Entity
	@Table(name = "LocationBitemporal")
	public static final class Bitemporal extends _Bitemporal<Location.Bitemporal, Location.Value> {
		private static final long serialVersionUID = -2132187534862370208L;
		
		protected Bitemporal() {}
	    private Bitemporal(Location.Value value, Interval validityInterval) {
	        super(value, validityInterval);
	    }
	    
	    @Override
	    public Bitemporal copyWith(Interval validityInterval) {
	    	return new Bitemporal(value, validityInterval);
	    }
	}

	@SuppressWarnings("deprecation")
	@OneToMany(fetch = FetchType.LAZY)
    @Cascade(value = { org.hibernate.annotations.CascadeType.ALL, org.hibernate.annotations.CascadeType.DELETE_ORPHAN })
    @JoinColumn(name="locationId")
    private Collection<UnitLocation.Value> unitLocations = new LinkedList<UnitLocation.Value>();	

	public Location() {
		super();
	}
	
    public Collection<UnitLocation.Value> getUnitLocations() {
		return unitLocations;
	}

	protected void setUnitLocations(Collection<UnitLocation.Value> unitLocations) {
		this.unitLocations = unitLocations;
	}

	public WrappedBitemporalProperty<Value, Bitemporal> getValues() {
    	return new WrappedBitemporalProperty<Value, Bitemporal>(values, new WrappedValueAccessor<Value,Bitemporal>() {
			private static final long serialVersionUID = 1L;

			@Override
			public Bitemporal wrapValue(Value value, Interval validityInterval) {
				Bitemporal bi = new Bitemporal(value, validityInterval);
				return bi;
			}
    	});
    }
}
